// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <pollux/vector/encoded_vector_copy.h>
#include <pollux/testing/gtest_utils.h>
#include <pollux/common/testutil/random_seed.h>
#include <pollux/vector/vector_fuzzer.h>
#include <pollux/testing/vector/vector_test_base.h>

namespace kumo::pollux {
    namespace {
        struct TestParams {
            using Type = std::tuple<bool>;
        };

        template<typename T>
        bool bufferEqual(
            const Buffer &actual,
            const Buffer &expected,
            vector_size_t size) {
            return std::memcmp(actual.as<T>(), expected.as<T>(), size * sizeof(T)) == 0;
        }

        void compareVectors(const VectorPtr &actual, const VectorPtr &expected) {
            if (expected->is_lazy()) {
                compareVectors(actual, BaseVector::loaded_vector_shared(expected));
                return;
            }
            ASSERT_EQ(actual->encoding(), expected->encoding());
            ASSERT_EQ(actual->size(), expected->size());
            if (expected->raw_nulls()) {
                ASSERT_TRUE(actual->raw_nulls());
                for (vector_size_t i = 0; i < actual->size(); ++i) {
                    ASSERT_EQ(
                        bits::isBitNull(actual->raw_nulls(), i),
                        bits::isBitNull(expected->raw_nulls(), i));
                }
            } else {
                ASSERT_FALSE(actual->raw_nulls());
            }
            switch (actual->encoding()) {
                case VectorEncoding::Simple::DICTIONARY:
                    ASSERT_TRUE(bufferEqual<vector_size_t>(
                        *actual->wrap_info(), *expected->wrap_info(), actual->size()));
                    compareVectors(actual->value_vector(), expected->value_vector());
                    break;
                case VectorEncoding::Simple::ROW: {
                    auto *actualRow = actual->as_checked<RowVector>();
                    auto *expectedRow = expected->as_checked<RowVector>();
                    for (column_index_t i = 0; i < actualRow->childrenSize(); ++i) {
                        compareVectors(actualRow->childAt(i), expectedRow->childAt(i));
                    }
                    break;
                }
                case VectorEncoding::Simple::MAP: {
                    auto *actualMap = actual->as_checked<MapVector>();
                    auto *expectedMap = expected->as_checked<MapVector>();
                    ASSERT_TRUE(bufferEqual<vector_size_t>(
                        *actualMap->offsets(), *expectedMap->offsets(), actualMap->size()));
                    ASSERT_TRUE(bufferEqual<vector_size_t>(
                        *actualMap->sizes(), *expectedMap->sizes(), actualMap->size()));
                    compareVectors(actualMap->mapKeys(), expectedMap->mapKeys());
                    compareVectors(actualMap->mapValues(), expectedMap->mapValues());
                    break;
                }
                case VectorEncoding::Simple::ARRAY: {
                    auto *actualArray = actual->as_checked<ArrayVector>();
                    auto *expectedArray = expected->as_checked<ArrayVector>();
                    ASSERT_TRUE(bufferEqual<vector_size_t>(
                        *actualArray->offsets(),
                        *expectedArray->offsets(),
                        actualArray->size()));
                    ASSERT_TRUE(bufferEqual<vector_size_t>(
                        *actualArray->sizes(), *expectedArray->sizes(), actualArray->size()));
                    compareVectors(actualArray->elements(), expectedArray->elements());
                    break;
                }
                default:
                    test::assertEqualVectors(expected, actual);
            }
        }

        class EncodedVectorCopyTest : public testing::TestWithParam<TestParams::Type>,
                                      public VectorBuilder {
        protected:
            static void SetUpTestSuite() {
                memory::MemoryManager::testingSetInstance({});
            }

            void copy(
                const VectorPtr &source,
                const melon::Range<const BaseVector::CopyRange *> &ranges,
                VectorPtr &target) {
                EncodedVectorCopyOptions options;
                options.pool = pool();
                options.reuseSource = reuseSource();
                withSource(source, [&](auto &source) {
                    encodedVectorCopy(options, source, ranges, target);
                });
            }

            void runTests(
                const VectorPtr &source,
                const melon::Range<const BaseVector::CopyRange *> &ranges,
                VectorPtr &target,
                const VectorPtr &expected,
                VectorPtr expectedNewSliceCopy = nullptr) { {
                    SCOPED_TRACE("New full copy");
                    BaseVector::CopyRange range = {0, 0, source->size()};
                    VectorPtr actual;
                    copy(source, melon::Range(&range, 1), actual);
                    compareVectors(actual, source);
                } {
                    SCOPED_TRACE("New slice copy");
                    POLLUX_CHECK_GE(source->size(), 3);
                    BaseVector::CopyRange range = {1, 0, source->size() - 2};
                    VectorPtr actual;
                    copy(source, melon::Range(&range, 1), actual);
                    if (!expectedNewSliceCopy) {
                        expectedNewSliceCopy = source->slice(range.sourceIndex, range.count);
                    }
                    compareVectors(actual, expectedNewSliceCopy);
                } {
                    SCOPED_TRACE("Immutable target");
                    auto actual = target;
                    copy(source, ranges, actual);
                    compareVectors(actual, expected);
                    ASSERT_NE(actual.get(), target.get());
                } {
                    SCOPED_TRACE("Mutable target");
                    POLLUX_CHECK_EQ(target.use_count(), 1);
                    copy(source, ranges, target);
                    compareVectors(target, expected);
                }
            }

            bool reuseSource() {
                return std::get<0>(GetParam());
            }

        private:
            template<typename F>
            void withSource(const VectorPtr &source, F &&f) {
                std::shared_ptr<memory::MemoryPool> sourcePool;
                VectorPtr sourceCopy;
                if (reuseSource()) {
                    sourceCopy = source;
                } else {
                    sourcePool = rootPool_->addLeafChild("SourcePool");
                    sourceCopy = source->copy_preserve_encodings(sourcePool.get());
                }
                f(sourceCopy);
            }
        };

        POLLUX_INSTANTIATE_TEST_SUITE_P(
            ,
            EncodedVectorCopyTest,
            testing::Combine(testing::Bool()));

        TEST_P(EncodedVectorCopyTest, constantToConstant) {
            auto source = make_constant<int64_t>(42, 10);
            auto target = make_constant<int64_t>(43, 10);
            BaseVector::CopyRange ranges[] = {{0, 1, 1}, {4, 3, 2}};
            auto expected = wrap_in_dictionary(
                make_indices({0, 1, 0, 1, 1, 0, 0, 0, 0, 0}),
                make_flat_vector<int64_t>({43, 42}));
            runTests(source, melon::Range(ranges, 2), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, constantToConstantSameValue) {
            auto source = make_constant<int64_t>(42, 10);
            auto target = make_constant<int64_t>(42, 5);
            BaseVector::CopyRange range = {2, 2, 9};
            auto expected = make_constant<int64_t>(42, 11);
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, constantToDictionary) {
            auto source = make_constant<int64_t>(42, 10);
            auto target =
                    wrap_in_dictionary(make_indices({1, 0}), make_flat_vector<int64_t>({43, 44}));
            BaseVector::CopyRange range = {3, 2, 2};
            auto expected = wrap_in_dictionary(
                make_indices({1, 0, 2, 2}), make_flat_vector<int64_t>({43, 44, 42}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, constantToFlat) {
            auto source = make_constant<int64_t>(42, 10);
            VectorPtr target = make_flat_vector<int64_t>({43, 44});
            BaseVector::CopyRange range = {3, 1, 2};
            auto expected = make_flat_vector<int64_t>({43, 42, 42});
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, dictionaryToConstant) {
            auto source = wrap_in_dictionary(
                make_indices({1, 0, 1, 0}), make_flat_vector<int64_t>({43, 44}));
            auto target = make_constant<int64_t>(42, 5);
            BaseVector::CopyRange range = {0, 1, 2};
            auto expected = wrap_in_dictionary(
                make_indices({0, 2, 1, 0, 0}), make_flat_vector<int64_t>({42, 43, 44}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, dictionaryToDictionary) {
            auto source = wrap_in_dictionary(
                make_indices({1, 0, 1, 0}), make_flat_vector<int64_t>({42, 43}));
            auto target = wrap_in_dictionary(
                make_indices({0, 1, 0}), make_flat_vector<int64_t>({44, 45}));
            BaseVector::CopyRange range = {1, 2, 2};
            auto expected = wrap_in_dictionary(
                make_indices({0, 1, 2, 3}), make_flat_vector<int64_t>({44, 45, 42, 43}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, dictionaryToFlat) {
            auto source = wrap_in_dictionary(
                make_indices({1, 0, 1, 0}), make_flat_vector<int64_t>({42, 43}));
            VectorPtr target = make_flat_vector<int64_t>({44, 45});
            BaseVector::CopyRange range = {0, 1, 2};
            auto expected = make_flat_vector<int64_t>({44, 43, 42});
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, dictionaryCompactBase) {
            auto sourceBase = make_flat_vector<int64_t>({42, 43});
            auto source = wrap_in_dictionary(make_indices({1, 0, 1, 0}), sourceBase); {
                SCOPED_TRACE("New full base");
                BaseVector::CopyRange ranges[] = {{0, 1, 1}, {1, 0, 1}};
                VectorPtr target;
                copy(source, melon::Range(ranges, 2), target);
                auto expected = wrap_in_dictionary(
                    make_indices({0, 1}), make_flat_vector<int64_t>({42, 43}));
                compareVectors(target, expected);
            } {
                SCOPED_TRACE("New compacted base");
                BaseVector::CopyRange ranges[] = {{1, 0, 1}, {3, 1, 1}};
                VectorPtr target;
                copy(source, melon::Range(ranges, 2), target);
                auto expectedBase =
                        reuseSource() ? sourceBase : make_flat_vector(std::vector<int64_t>({42}));
                auto expected = wrap_in_dictionary(make_indices({0, 0}), expectedBase);
                compareVectors(target, expected);
                if (reuseSource()) {
                    ASSERT_EQ(target->value_vector().get(), sourceBase.get());
                }
            } {
                SCOPED_TRACE("Compact target base");
                auto target = wrap_in_dictionary(
                    make_indices({0, 0, 2, 2}), make_flat_vector<int64_t>({44, 45, 46}));
                BaseVector::CopyRange range = {0, 2, 4};
                copy(source, melon::Range(&range, 1), target);
                auto expected = wrap_in_dictionary(
                    make_indices({0, 0, 2, 1, 2, 1}), make_flat_vector<int64_t>({44, 42, 43}));
                compareVectors(target, expected);
            } {
                SCOPED_TRACE("Drop unused target base tail");
                auto targetBase = make_flat_vector<int64_t>({44, 45, 46});
                auto *targetBasePtr = targetBase.get();
                auto target =
                        wrap_in_dictionary(make_indices({0, 1, 2}), std::move(targetBase));
                target->resize(0);
                BaseVector::CopyRange range = {0, 0, 4};
                copy(source, melon::Range(&range, 1), target);
                compareVectors(target, source);
                ASSERT_EQ(target->value_vector().get(), targetBasePtr);
            }
        }

        TEST_P(EncodedVectorCopyTest, allNullsDictionary) {
            auto source = BaseVector::wrap_in_dictionary(
                make_nulls({true, true, true}),
                make_indices({0, 1, 2}),
                3,
                make_flat_vector<int64_t>({42, 43, 44})); {
                SCOPED_TRACE("New full copy");
                BaseVector::CopyRange range = {0, 0, source->size()};
                VectorPtr actual;
                copy(source, melon::Range(&range, 1), actual);
                test::assertEqualVectors(source, actual);
            } {
                SCOPED_TRACE("New slice copy");
                BaseVector::CopyRange range = {1, 0, source->size() - 2};
                VectorPtr actual;
                copy(source, melon::Range(&range, 1), actual);
                test::assertEqualVectors(
                    source->slice(range.sourceIndex, range.count), actual);
            }
            auto target =
                    wrap_in_dictionary(make_indices({0, 1}), make_flat_vector<int64_t>({45, 46}));
            std::vector<BaseVector::CopyRange> ranges = {{0, 2, 3}};
            auto expected = BaseVector::wrap_in_dictionary(
                make_nulls({false, false, true, true, true}),
                make_indices({0, 1, 0, 0, 0}),
                5,
                make_flat_vector<int64_t>({45, 46})); {
                SCOPED_TRACE("Immutable target");
                auto actual = target;
                copy(source, ranges, actual);
                compareVectors(actual, expected);
                ASSERT_NE(actual.get(), target.get());
            } {
                SCOPED_TRACE("Mutable target");
                POLLUX_CHECK_EQ(target.use_count(), 1);
                copy(source, ranges, target);
                compareVectors(target, expected);
            }
        }

        TEST_P(EncodedVectorCopyTest, flatToConstant) {
            auto source = make_flat_vector<int64_t>({43, 44, 45});
            auto target = make_constant<int64_t>(42, 5);
            BaseVector::CopyRange range = {0, 1, 2};
            auto expected = wrap_in_dictionary(
                make_indices({0, 1, 2, 0, 0}), make_flat_vector<int64_t>({42, 43, 44}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, flatToDictionary) {
            auto source = make_flat_vector<int64_t>({42, 43, 44});
            auto target = wrap_in_dictionary(
                make_indices({0, 1, 0}), make_flat_vector<int64_t>({45, 46}));
            BaseVector::CopyRange range = {0, 1, 2};
            auto expected = wrap_in_dictionary(
                make_indices({0, 1, 2}), make_flat_vector<int64_t>({45, 42, 43}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, flatToFlat) {
            VectorPtr source = make_flat_vector<int64_t>({42, 43, 44});
            VectorPtr target = make_flat_vector<int64_t>({45, 46, 47});
            BaseVector::CopyRange range = {0, 1, 2};
            auto expected = make_flat_vector<int64_t>({45, 42, 43});
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, flatRow) {
            auto source = make_row_vector({make_flat_vector<int64_t>({1, 2, 3})});
            VectorPtr target = make_row_vector({make_flat_vector<int64_t>({4, 5, 6})});
            BaseVector::CopyRange range = {1, 2, 2};
            auto expected = make_row_vector({make_flat_vector<int64_t>({4, 5, 2, 3})});
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, constant_row) {
            auto type = ROW({"c0"}, {BIGINT()});
            auto source = make_constant_row(type, variant::row({42ll}), 3);
            auto target = make_constant_row(type, variant::row({43ll}), 2);
            BaseVector::CopyRange range = {0, 2, 2};
            auto expected = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}),
                make_row_vector({make_flat_vector<int64_t>({43, 42})}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, dictionaryOfRow) {
            auto source = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}),
                make_row_vector({make_flat_vector<int64_t>({42, 43})}));
            auto target = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}),
                make_row_vector({make_flat_vector<int64_t>({44, 45})}));
            BaseVector::CopyRange range = {0, 4, 4};
            auto expected = wrap_in_dictionary(
                make_indices({0, 0, 1, 1, 2, 2, 3, 3}),
                make_row_vector({make_flat_vector<int64_t>({44, 45, 42, 43})}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, rowOfDictionary) {
            auto source = make_row_vector({
                wrap_in_dictionary(
                    make_indices({0, 0, 1, 1}), make_flat_vector<int64_t>({42, 43})),
            });
            VectorPtr target = make_row_vector({
                wrap_in_dictionary(
                    make_indices({0, 0, 1, 1}), make_flat_vector<int64_t>({44, 45})),
            });
            BaseVector::CopyRange range = {0, 4, 4};
            auto expected = make_row_vector({
                wrap_in_dictionary(
                    make_indices({0, 0, 1, 1, 2, 2, 3, 3}),
                    make_flat_vector<int64_t>({44, 45, 42, 43})),
            });
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, constantRowToFlat) {
            VectorPtr target = make_row_vector({make_flat_vector<int64_t>({42, 43, 44})});
            auto source =
                    make_constant_row(as_row_type(target->type()), variant::row({45ll}), 3);
            BaseVector::CopyRange range = {0, 2, 3};
            auto expected = wrap_in_dictionary(
                make_indices({0, 1, 3, 3, 3}),
                make_row_vector({make_flat_vector<int64_t>({42, 43, 44, 45})}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, dictionaryRowToFlat) {
            auto source = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}),
                make_row_vector({make_flat_vector<int64_t>({42, 43})}));
            VectorPtr target = make_row_vector({make_flat_vector<int64_t>({44, 45})});
            BaseVector::CopyRange range = {1, 2, 2};
            auto expected = wrap_in_dictionary(
                make_indices({0, 1, 2, 3}),
                make_row_vector({make_flat_vector<int64_t>({44, 45, 42, 43})}));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, flatMap) {
            auto sourceElements = make_flat_vector<int64_t>({1, 2, 3});
            auto targetElements = make_flat_vector<int64_t>({4, 5, 6});
            auto source = make_map_vector({0, 1, 2}, sourceElements, sourceElements);
            VectorPtr target = make_map_vector({0, 1, 2}, targetElements, targetElements);
            BaseVector::CopyRange range = {1, 2, 2};
            auto expectedElements = make_flat_vector<int64_t>({4, 5, 6, 2, 3});
            auto expected = std::make_shared<MapVector>(
                pool(),
                source->type(),
                nullptr,
                4,
                make_indices({0, 1, 3, 4}),
                make_indices({1, 1, 1, 1}),
                expectedElements,
                expectedElements);
            auto expectedNewSliceCopy = std::make_shared<MapVector>(
                pool(),
                source->type(),
                nullptr,
                1,
                make_indices({0}),
                make_indices({1}),
                make_flat_vector(std::vector<int64_t>({2})),
                make_flat_vector(std::vector<int64_t>({2})));
            runTests(
                source, melon::Range(&range, 1), target, expected, expectedNewSliceCopy);
        }

        TEST_P(EncodedVectorCopyTest, constantMap) {
            auto sourceElements = make_flat_vector<int64_t>({42, 43});
            auto source = BaseVector::wrap_in_constant(
                3, 1, make_map_vector({0, 1}, sourceElements, sourceElements));
            auto targetElements = make_flat_vector<int64_t>({44, 45});
            auto target = BaseVector::wrap_in_constant(
                3, 1, make_map_vector({0, 1}, targetElements, targetElements));
            BaseVector::CopyRange range = {1, 2, 2};
            auto expected = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}),
                make_map_vector(
                    {0, 1},
                    make_flat_vector<int64_t>({45, 43}),
                    make_flat_vector<int64_t>({45, 43})));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, dictionaryMap) {
            auto sourceElements = make_flat_vector<int64_t>({42, 43});
            auto source = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}),
                make_map_vector({0, 1}, sourceElements, sourceElements));
            auto targetElements = make_flat_vector<int64_t>({44, 45});
            auto target = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}),
                make_map_vector({0, 1}, targetElements, targetElements));
            BaseVector::CopyRange range = {1, 1, 2};
            auto expectedElements = make_flat_vector<int64_t>({44, 45, 42, 43});
            auto expected = wrap_in_dictionary(
                make_indices({0, 2, 3, 1}),
                make_map_vector({0, 1, 2, 3}, expectedElements, expectedElements));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, mapCompact) {
            auto sourceElements = make_flat_vector<int64_t>({42, 43, 44});
            auto source = make_map_vector({0, 1, 2}, sourceElements, sourceElements);
            VectorPtr target = std::make_shared<MapVector>(
                pool(),
                source->type(),
                nullptr,
                1,
                make_indices({1}),
                make_indices({1}),
                make_flat_vector<int64_t>({45, 46, 47}),
                make_flat_vector<int64_t>({45, 46, 47}));
            BaseVector::CopyRange range = {1, 1, 1};
            auto expectedNewSliceCopy = std::make_shared<MapVector>(
                pool(),
                source->type(),
                nullptr,
                1,
                make_indices({0}),
                make_indices({1}),
                make_flat_vector(std::vector<int64_t>({43})),
                make_flat_vector(std::vector<int64_t>({43})));
            auto expected = std::make_shared<MapVector>(
                pool(),
                source->type(),
                nullptr,
                2,
                make_indices({0, 1}),
                make_indices({1, 1}),
                make_flat_vector<int64_t>({46, 43}),
                make_flat_vector<int64_t>({46, 43}));
            runTests(
                source, melon::Range(&range, 1), target, expected, expectedNewSliceCopy);
        }

        TEST_P(EncodedVectorCopyTest, arrayCompactFullReplacement) {
            auto source =
                    make_array_vector({0, 1, 2}, make_flat_vector<int64_t>({42, 43, 44}));
            auto targetElements = make_flat_vector<int64_t>({45, 46, 47});
            auto *targetElementsPtr = targetElements.get();
            VectorPtr target = make_array_vector({0, 1, 2}, std::move(targetElements));
            target->resize(0);
            BaseVector::CopyRange range = {0, 0, 3};
            copy(source, melon::Range(&range, 1), target);
            compareVectors(target, source);
            ASSERT_EQ(
                target->as_checked<ArrayVector>()->elements().get(), targetElementsPtr);
        }

        TEST_P(EncodedVectorCopyTest, allNullsMap) {
            auto source = make_all_null_map_vector(3, BIGINT(), BIGINT());
            VectorPtr target = make_all_null_map_vector(3, BIGINT(), BIGINT());
            BaseVector::CopyRange range = {1, 2, 2};
            auto expected = make_all_null_map_vector(4, BIGINT(), BIGINT());;
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, flatArray) {
            auto sourceElements = make_flat_vector<int64_t>({1, 2, 3});
            auto targetElements = make_flat_vector<int64_t>({4, 5, 6});
            auto source = make_array_vector({0, 1, 2}, sourceElements);
            VectorPtr target = make_array_vector({0, 1, 2}, targetElements);
            BaseVector::CopyRange range = {1, 2, 2};
            auto expectedElements = make_flat_vector<int64_t>({4, 5, 6, 2, 3});
            auto expected = std::make_shared<ArrayVector>(
                pool(),
                source->type(),
                nullptr,
                4,
                make_indices({0, 1, 3, 4}),
                make_indices({1, 1, 1, 1}),
                expectedElements);
            auto expectedNewSliceCopy = std::make_shared<ArrayVector>(
                pool(),
                source->type(),
                nullptr,
                1,
                make_indices({0}),
                make_indices({1}),
                make_flat_vector(std::vector<int64_t>({2})));
            runTests(
                source, melon::Range(&range, 1), target, expected, expectedNewSliceCopy);
        }

        TEST_P(EncodedVectorCopyTest, constantArray) {
            auto sourceElements = make_flat_vector<int64_t>({42, 43});
            auto source =
                    BaseVector::wrap_in_constant(3, 1, make_array_vector({0, 1}, sourceElements));
            auto targetElements = make_flat_vector<int64_t>({44, 45});
            auto target =
                    BaseVector::wrap_in_constant(3, 1, make_array_vector({0, 1}, targetElements));
            BaseVector::CopyRange range = {1, 2, 2};
            auto expected = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}),
                make_array_vector({0, 1}, make_flat_vector<int64_t>({45, 43})));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, dictionaryArray) {
            auto sourceElements = make_flat_vector<int64_t>({42, 43});
            auto source = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}), make_array_vector({0, 1}, sourceElements));
            auto targetElements = make_flat_vector<int64_t>({44, 45});
            auto target = wrap_in_dictionary(
                make_indices({0, 0, 1, 1}), make_array_vector({0, 1}, targetElements));
            BaseVector::CopyRange range = {1, 1, 2};
            auto expectedElements = make_flat_vector<int64_t>({44, 45, 42, 43});
            auto expected = wrap_in_dictionary(
                make_indices({0, 2, 3, 1}),
                make_array_vector({0, 1, 2, 3}, expectedElements));
            runTests(source, melon::Range(&range, 1), target, expected);
        }

        TEST_P(EncodedVectorCopyTest, fuzzer) {
            VectorFuzzer::Options fuzzerOptions;
            fuzzerOptions.allowLazyVector = reuseSource();
            fuzzerOptions.nullRatio = 0.05;
            auto seed = common::testutil::getRandomSeed(42);
            VectorFuzzer fuzzer(fuzzerOptions, pool(), seed);
            fuzzer::FuzzerGenerator rng(seed);
#ifndef NDEBUG
            constexpr int kNumIterations = 20;
#else
  constexpr int kNumIterations = 1000;
#endif
            for (int i = 0; i < kNumIterations; ++i) {
                auto type = fuzzer.randType();
                SCOPED_TRACE(fmt::format("i={} type={}", i, type->toString()));
                auto source = fuzzer.fuzz(type);
                BaseVector::CopyRange range;
                range.sourceIndex = melon::Random::rand32(source->size() - 1, rng);
                range.count =
                        melon::Random::rand32(1, source->size() - range.sourceIndex, rng); {
                    SCOPED_TRACE("Null target");
                    VectorPtr target;
                    range.targetIndex = 0;
                    copy(source, melon::Range(&range, 1), target);
                    test::assertEqualVectors(
                        source->slice(range.sourceIndex, range.count), target);
                }
                auto target = fuzzer.fuzz(type);
                range.targetIndex = melon::Random::rand32(0, target->size() - 1, rng);
                auto makeExpected = [&](auto &expected) {
                    if (expected->size() < range.targetIndex + range.count) {
                        expected->resize(range.targetIndex + range.count);
                    }
                    expected->copy_ranges(source.get(), melon::Range(&range, 1));
                }; {
                    SCOPED_TRACE("Immutable target");
                    auto actual = target;
                    copy(source, melon::Range(&range, 1), actual);
                    auto expected = BaseVector::copy(*target);
                    makeExpected(expected);
                    test::assertEqualVectors(expected, actual);
                } {
                    SCOPED_TRACE("Mutable target");
                    auto expected = BaseVector::copy(*target);
                    copy(source, melon::Range(&range, 1), target);
                    makeExpected(expected);
                    test::assertEqualVectors(expected, target);
                }
            }
        }
    } // namespace
} // namespace kumo::pollux
